# -*- coding:utf-8 -*-

import json
import os
from common import ReadConfig
from common.Log import MyLog
from common.Mock import MyMock
from common.OperationExcel import OperationExcel

_TEMP_PATH = os.path.dirname(os.path.abspath(__file__)) + r"/../tmp/"


class OperationJson:

    def __init__(self):
        self.result = None
        self.__create_json_path()

    def search_key(self, data, key):
        """
        以列表形式返回字典中对应key的值
        :param data:
        :param key:
        :return:
        """
        self.__search(data, key)
        return self.result

    def __search(self, json_obj, key):
        """
        遍历json中的key
        :param json_obj:
        :param key:
        :return:
        """
        for k, v in json_obj.items():
            if k == key:
                self.result = v
            if isinstance(v, dict):
                self.__search(v, key)
            if isinstance(v, list):
                for i in v:
                    if isinstance(i, dict):
                        self.__search(i, key)

    @staticmethod
    def __save_middle_data(case_name, key_word, key_value):
        """
        按照用例名称保存中间数据
        :param case_name:
        :param key_word:
        :param key_value:
        :return:
        """
        try:
            if os.path.exists(_TEMP_PATH + "json.json"):
                fp = open(file=_TEMP_PATH + "json.json", mode='r', encoding='utf-8')
                res = json.load(fp)
                if res or case_name not in res:
                    res[case_name] = {key_word: key_value}
                else:
                    res[case_name][key_word] = key_value
                fp.close()
                fp = open(file=_TEMP_PATH + "json.json", mode='w', encoding='utf-8')
                json.dump(res, fp=fp, sort_keys=True, indent=4, ensure_ascii=False)
                fp.close()
            else:
                fp = open(file=_TEMP_PATH + "json.json", mode='w', encoding='utf-8')
                res = {case_name: {key_word: key_value}}
                json.dump(res, fp=fp, sort_keys=True, indent=4, ensure_ascii=False)
        except json.decoder.JSONDecodeError:
            MyLog().logger.error("解析json文件失败, 请检查json文件")

    def save_middle_data(self, case, response):
        """
        根据响应数据保存用例的中间数据
        :param case:
        :param response:
        :return:
        """
        middle_data = case['middle_data']
        if middle_data:
            for i in middle_data:
                value = self.search_key(response, i)
                self.__save_middle_data(case['case_name'], i, value)

    @staticmethod
    def __create_json_path():
        """
        创建json目录
        :return:
        """
        if not os.path.exists(_TEMP_PATH):
            os.mkdir(_TEMP_PATH)

    @staticmethod
    def __create_json_file():
        """
        创建json目录
        :return:
        """
        if not os.path.exists(_TEMP_PATH + 'json.json'):
            fp = open(_TEMP_PATH + 'json.json', 'w', encoding='utf-8')
            fp.write('{}')
            fp.close()

    @staticmethod
    def delete_depend_data(case):
        """
        删除用例依赖数据
        :param case:
        :return:
        """
        depend_case = case['depend_case']
        try:
            fp = open(file=_TEMP_PATH + "json.json", mode='r', encoding='utf-8')
            dict_ = json.load(fp)
            for key in depend_case:
                del dict_[key]
            fp.close()
            fp = open(file=_TEMP_PATH + "json.json", mode='w', encoding='utf-8')
            json.dump(dict_, fp=fp, sort_keys=True, indent=4, ensure_ascii=False)
            fp.close()
        except json.decoder.JSONDecodeError:
            MyLog().logger.error("解析json文件失败, 请检查json文件")

    def update_request_url(self, case):
        """
        更新用例的请求地址
        :param case:
        :return:
        """
        request_url = case['request_url']
        update_url = case['update_url']
        if update_url:
            self.__create_json_file()
            fp = open(file=_TEMP_PATH + "json.json", mode='r', encoding='utf-8')
            dict_ = json.load(fp)
            for k, v in update_url.items():
                if k not in dict_:
                    ExecCase.exec_case(OperationExcel().get_case_by_case_name(k))
                rfp = open(file=_TEMP_PATH + "json.json", mode='r', encoding='utf-8')
                dict_ = json.load(rfp)
                rfp.close()
                value = dict_[k][v]
                request_url = request_url + '/' + value
            case['request_url'] = request_url
        return case

    def update_request_data_from_depend_data(self, case):
        """
        将依赖数据加入请求数据后返回用例，没有则直接返回用例
        :param case:
        :return:
        """
        depend_case = case['depend_case']
        if depend_case:
            self.__create_json_file()
            fp = open(file=_TEMP_PATH + "json.json", mode='r', encoding='utf-8')
            dict_ = json.load(fp)
            for case_name in depend_case:
                lists = depend_case[case_name]
                # 如果文件中存有依赖数据，则从文件中读取, 否则执行依赖用例生成数据之后再添加
                if case_name not in dict_:
                    ExecCase.exec_case(OperationExcel().get_case_by_case_name(case_name))
                rfp = open(file=_TEMP_PATH + "json.json", mode='r', encoding='utf-8')
                dict_ = json.load(rfp)
                rfp.close()
                for key_word in lists:
                    value = dict_[case_name][key_word]
                    case['request_data'][key_word] = value
            fp.close()
            return case
        else:
            return case


class ExecCase:
    @staticmethod
    def exec_case(case):
        """
        执行用例
        :param case:
        :return:
        """
        MyLog().logger.info(r"----- start case " + case['case_name'] + " -----")
        MyLog().logger.info(r"----- case description:" + case['case_description'])
        MyLog().logger.info(r"----- module:" + case['module_name'])
        MyLog().logger.info(r"----- request method:" + case['request_method'])
        MyLog().logger.info(r"----- request url:" + json.dumps(case['request_url']))
        MyLog().logger.info(r"----- request data:" + json.dumps(case['request_data'], ensure_ascii=False))
        MyLog().logger.info(r"----- expect result:" + json.dumps(case['expect_res'], ensure_ascii=False))
        # 判断是否有依赖数据
        oj = OperationJson()
        if case['depend_case'] and not ReadConfig.MOCK:
            case = oj.update_request_data_from_depend_data(case)
        # 是否需要更新请求地址
        if case['update_url'] and not ReadConfig.MOCK:
            case = oj.update_request_url(case)
        # 执行请求
        response = MyMock().mock_requests(request_method=case['request_method'],
                                          url=case['request_url'],
                                          expect_data=case['expect_res'],
                                          data=case['request_data']
                                          )
        if not ReadConfig.MOCK:
            response = json.loads(response)
            # 判断是否有中间数据
            if case['middle_data']:
                OperationJson().save_middle_data(case, response)
            # 判断是否删除依赖数据
            if case['del_depend']:
                OperationJson().delete_depend_data(case)
        MyLog().logger.info(r"----- real result:" + json.dumps(response, ensure_ascii=False))
        MyLog().logger.info(r"----- real request data:" + json.dumps(case['request_data'], ensure_ascii=False))
        return response
